package com.huas.filter;



import com.huas.config.SpringConfig;
import com.huas.constant.MessageConstant;
import com.huas.constant.UserConstant;
import com.huas.entity.LoginUser;
import com.huas.exception.AccountException;
import com.huas.properties.JwtProperties;
import com.huas.utils.JwtUtil;
import com.huas.utils.RedisUtils;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.servlet.HandlerExceptionResolver;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Objects;

@Component
@Slf4j
public class SecurityFilter extends OncePerRequestFilter {
    @Resource
    private RedisUtils redisUtils;
    @Resource
    private JwtProperties jwtProperties;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        //获取token
        String url = request.getRequestURI();
        String jwt = request.getHeader(UserConstant.ACCOUNT_TOKEN);
        if (url.contains(UserConstant.LOGIN_URL) || url.contains(UserConstant.LOGIN_CAPTCHA) || url.contains(UserConstant.REGISTER_URL)){
            //放行登录、注册或者获取验证码请求
            filterChain.doFilter(request,response);
            return;
        }
        //解析token
        Integer id;
        /**1、使用HandlerExceptionResolver的resolveException方法，将要抛出的异常作为参数传入
         * 该异常会被自定义的全局异常处理器捕获处理，返回最终结果
         * 2、通过ApplicationContext的getBean方法来获取防止通过注解注入导致的空指针异常
         */
        HandlerExceptionResolver handlerExceptionResolver = (HandlerExceptionResolver) SpringConfig.getBean("handlerExceptionResolver");
        try {
            Claims claims = JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(),jwt);
            id = (Integer) claims.get(UserConstant.ACCOUNT_ID);
        } catch (Exception e) {
            //判断是否为用户未登录异常，设置状态码为401，与前端响应拦截器对应
            //当前端接收到401状态码时跳转到登录界面
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            handlerExceptionResolver.resolveException(request,response,
                    null,new AccountException(MessageConstant.USER_NOT_LOGIN));
            return;
        }
        //从redis获取用户信息
        LoginUser loginUser = (LoginUser) redisUtils.get(UserConstant.LOGIN_MESSAGE + id);
        if(Objects.isNull(loginUser)){
            //判断是否为用户未登录异常，设置状态码为401，与前端响应拦截器对应
            //当前端接收到401状态码时跳转到登录界面
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            handlerExceptionResolver.resolveException(request,response,
                    null,new AccountException(MessageConstant.USER_NOT_LOGIN));
            return;
        }
        //将用户信息存入SecurityContextHolder
        UsernamePasswordAuthenticationToken authenticationToken =
                /*
                第三个参数：调用UserDetails实现类重写的getAuthorities()方法，获取权限集合
                 */
                new UsernamePasswordAuthenticationToken(loginUser,null,loginUser.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        //放行
        filterChain.doFilter(request, response);

    }
}
